﻿using System.Linq.Expressions;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;

namespace Devonline.AspNetCore;

/// <summary>
/// 公共数据处理服务
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
/// <typeparam name="TKey">键类型</typeparam>
public interface IDataService<TDbContext, TEntitySet, TKey> :
    IServiceBase<TDbContext, TKey>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<TKey>
    where TKey : IConvertible
{
    #region 数据查询方法
    /// <summary>
    /// 统一数据源查询入口, 可缓存数据源, 仅返回当前类型引用
    /// </summary>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable();
    /// <summary>
    /// 统一数据源查询入口, 可缓存数据源, 仅返回当前类型引用
    /// </summary>
    /// <param name="predicate">过滤条件</param>
    /// <returns></returns>
    IQueryable<TEntitySet> GetQueryable(Expression<Func<TEntitySet, bool>> predicate);
    /// <summary>
    /// 根据 id 获取对象
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<TEntitySet?> GetAsync(TKey id);
    /// <summary>
    /// 从 QueryOptions 和上下文自动获取查询表达式的内容并执行查询返回分页的结果
    /// 暂不支持 orderby, select 和 expand 表达式
    /// </summary>
    /// <returns></returns>
    Task<PagedResult> GetPagedResultAsync();
    /// <summary>
    /// 适用于新增时判断对象是否存在, 存在则抛出异常
    /// </summary>
    /// <param name="id">业务数据编号</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task ThrowIfExistAsync(TKey? id);
    /// <summary>
    /// 适用于更新时判断当前对象是否存在, 存在则返回按 Id 查询的结果, 不存在则抛出异常
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task<TEntitySet> GetIfExistAsync(TKey id);
    /// <summary>
    /// 获取业务数据的集合成员, 成员是附加信息, 附件及特定类型的附属集合
    /// </summary>
    /// <typeparam name="TElement">附加信息, 附件或附属集合的类型</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    IEnumerable<TElement>? GetCollectionMembers<TElement>(TEntitySet entitySet) where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 数据操作方法
    /// <summary>
    /// 新增阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    /// <exception cref="BadHttpRequestException"></exception>
    Task UniqueAsync(TEntitySet entitySet);
    /// <summary>
    /// 单个数据对象的新增, 自动验证重复
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync(TEntitySet entitySet);
    /// <summary>
    /// 批量新增, 自动验证重复
    /// </summary>
    /// <param name="entitySets">业务数据</param>
    /// <returns></returns>
    Task<IEnumerable<TEntitySet>> AddsAsync(IEnumerable<TEntitySet> entitySets);
    /// <summary>
    /// 更新阶段判断满足条件的数据是否存在, 存在则抛出异常, 不存在则执行基类预定义赋值操作
    /// </summary>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync(TEntitySet entitySet, bool isLogical = false);
    /// <summary>
    /// 批量新增或修改数据对象模型到当前上下文, 但不提交
    /// </summary>
    /// <param name="entitySets">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<IEnumerable<TEntitySet>> AddsOrUpdatesAsync(IEnumerable<TEntitySet> entitySets, bool isLogical = false);
    /// <summary>
    /// 删除记录
    /// </summary>
    /// <param name="id">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync(TKey id, bool isLogical = false);
    /// <summary>
    /// 批量删除记录
    /// </summary>
    /// <param name="ids">业务数据主键</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeletesAsync(IEnumerable<TKey> ids, bool isLogical = false);
    /// <summary>
    /// 刷新缓存
    /// </summary>
    /// <returns></returns>
    Task RefreshCacheAsync();
    #endregion

    #region 数据带附属信息的数据操作方法
    #region 新增部分
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAdditional>(TEntitySet entitySet) where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件一并新增
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的的某一种集合成员一并新增
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及附件一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TElement : class, IEntitySet<TKey> where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 此重载新增方法会同时将当前业务数据的附加信息, 附件及集合元素数据一并新增
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据的集合元素数据</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task<TEntitySet> AddAsync<TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 修改部分
    /// <summary>
    /// 重载的更新方法会同时将当前类型的附加信息一并更新
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAdditional>(TEntitySet entitySet, bool isLogical = false) where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件一并更新
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及附件一并更新
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAdditional, TAttachment>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAdditional, TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet"></param>
    /// <param name="attachments"></param>
    /// <param name="elements"></param>
    /// <param name="foreignKey"></param>
    /// <param name="isLogical"></param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的更新方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并更新
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="attachments">附件</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task<TEntitySet> UpdateAsync<TAdditional, TAttachment, TElement>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, IEnumerable<TAttachment>? attachments = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 删除部分
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息一并删除
    /// </summary>
    /// <typeparam name="TAdditional">集合元素数据类型, 此时的集合是 IAdditional</typeparam>
    /// <param name="additionalId">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAdditional>(TKey additionalId, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件一并删除
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="businessKey">业务主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAttachment>(TKey businessKey, string? businessType = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及附件一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAdditional, TAttachment>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAdditional, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAttachment, TElement>(TKey id, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 重载的删除方法会同时将当前业务数据的附加信息, 附件及业务数据引用的数据集合一并删除
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="elements">业务数据引用的数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteAsync<TAdditional, TAttachment, TElement>(TKey id, IEnumerable<TAdditional>? additionals = default, string? businessType = default, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey> where TAttachment : class, IAttachment<TKey> where TElement : class, IEntitySet<TKey>;
    #endregion    
    #endregion

    #region 业务附加信息类操作方法
    /// <summary>
    /// 新增业务数据的附加信息
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <returns></returns>
    Task AddAdditionalsAsync<TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default) where TAdditional : class, IAdditional<TKey>;
    /// <summary>
    /// 更新业务数据的附加信息
    /// </summary>
    /// <typeparam name="TAdditional">业务数据的附加信息 IAdditional</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="additionals">附加数据集合</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task UpdateAdditionalsAsync<TAdditional>(TEntitySet entitySet, IEnumerable<TAdditional>? additionals = default, bool isLogical = false) where TAdditional : class, IAdditional<TKey>;
    #endregion

    #region 业务数据引用关系的集合类操作方法
    /// <summary>
    /// 新增业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <returns></returns>
    Task AddCollectionAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default) where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 更新业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task UpdateCollectionAsync<TElement>(TEntitySet entitySet, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>;
    /// <summary>
    /// 删除业务数据对象中 TElement 类型的集合对象
    /// </summary>
    /// <typeparam name="TElement">业务数据的集合元素数据 IEntitySet</typeparam>
    /// <param name="id">业务数据主键</param>
    /// <param name="elements">引用数据集合</param>
    /// <param name="foreignKey">外键字段名</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns></returns>
    Task DeleteCollectionAsync<TElement>(TKey id, IEnumerable<TElement>? elements = default, string? foreignKey = default, bool isLogical = false) where TElement : class, IEntitySet<TKey>;
    #endregion

    #region 文件及业务数据附件操作方法
    /// <summary>
    /// 新增附件
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task AddAttachmentsAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default) where TAttachment : class, IAttachment<TKey>;
    /// <summary>
    /// 修改附件, 保留旧附件, 新增新附件, 返回待删除文件列表
    /// </summary>
    /// <typeparam name="TAttachment">业务数据的附件 IAttachment</typeparam>
    /// <param name="entitySet">业务数据</param>
    /// <param name="attachments">附件集合</param>
    /// <param name="businessType">业务类型</param>
    /// <param name="isLogical">是否逻辑操作, 默认不是</param>
    /// <returns>待删除文件列表, 请在数据库事物提交成功后删除列表中的文件</returns>
    Task<IEnumerable<string>> UpdateAttachmentsAsync<TAttachment>(TEntitySet entitySet, IEnumerable<TAttachment>? attachments = default, string? businessType = default, bool isLogical = false) where TAttachment : class, IAttachment<TKey>;
    #endregion
}

/// <summary>
/// 字符串作为主键的默认实现接口
/// </summary>
/// <typeparam name="TDbContext">数据库上下文</typeparam>
/// <typeparam name="TEntitySet">业务数据类型</typeparam>
public interface IDataService<TDbContext, TEntitySet> :
    IDataService<TDbContext, TEntitySet, string>,
    IServiceBase<TDbContext>
    where TDbContext : DbContext
    where TEntitySet : class, IEntitySet<string>
{ }